

//------------------------------------------------------------------------------
// The confidential and proprietary information contained in this file may
// only be used by a person authorised under and to the extent permitted
// by a subsisting licensing agreement from ARM Limited.
//
//            (C) COPYRIGHT 2012 ARM Limited.
//                ALL RIGHTS RESERVED
//
// This entire notice must be reproduced on all copies of this file
// and copies of this file may only be made by a person if such person is
// permitted to do so under the terms of a subsisting license agreement
// from ARM Limited.
//------------------------------------------------------------------------------
// Version and Release Control Information:
//
// File Revision       : 133672
// File Date           :  2012-07-13 14:56:27 +0100 (Fri, 13 Jul 2012)
// Release Information : PL401-r0p1-00eac0
//------------------------------------------------------------------------------
// Purpose : RTL of APB Master Interface Block
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// AMIB Defines
//------------------------------------------------------------------------------
`include "Axi.v"
`include "nic400_amib_perip1_gp_apb4_defs_ysyx_rv32.v"


//------------------------------------------------------------------------------
// Module Declaration
//------------------------------------------------------------------------------
module nic400_amib_perip1_gp_apb4_apb_m_ysyx_rv32
(
  // Global signals
  aclk,
  aresetn,

  // A Channel
  awrite,
  aid,
  aaddr,
  alen,
  asize,
  aburst,
  aregion,
  aprot,

  avalid,
  aready,

  // D Channel
  dbnr,
  did,
  ddata,
  dresp,
  dlast,
  dvalid,
  dready,

  // W Channel
  wdata,
  wstrb,
  wlast,
  wvalid,
  wready,

  // APB3 Interface
  pclken,
  psel_archinfo_slv_apb4_i,
  psel_crc_slv_apb4_i,
  psel_spi0_slv_apb4_i,
  psel_spi1_slv_apb4_i,
  psel_ps2_slv_apb4_i,
  psel_rng_slv_apb4_i,
  psel_tim0_slv_apb4_i,
  psel_tim1_slv_apb4_i,
  psel_tim2_slv_apb4_i,
  psel_tim3_slv_apb4_i,
  psel_psram_slv_apb4_i,
  pready_archinfo_slv_apb4_i,
  pready_crc_slv_apb4_i,
  pready_spi0_slv_apb4_i,
  pready_spi1_slv_apb4_i,
  pready_ps2_slv_apb4_i,
  pready_rng_slv_apb4_i,
  pready_tim0_slv_apb4_i,
  pready_tim1_slv_apb4_i,
  pready_tim2_slv_apb4_i,
  pready_tim3_slv_apb4_i,
  pready_psram_slv_apb4_i,
  pslverr_archinfo_slv_apb4_i,
  pslverr_crc_slv_apb4_i,
  pslverr_spi0_slv_apb4_i,
  pslverr_spi1_slv_apb4_i,
  pslverr_ps2_slv_apb4_i,
  pslverr_rng_slv_apb4_i,
  pslverr_tim0_slv_apb4_i,
  pslverr_tim1_slv_apb4_i,
  pslverr_tim2_slv_apb4_i,
  pslverr_tim3_slv_apb4_i,
  pslverr_psram_slv_apb4_i,
  prdata_archinfo_slv_apb4_i,
  prdata_crc_slv_apb4_i,
  prdata_spi0_slv_apb4_i,
  prdata_spi1_slv_apb4_i,
  prdata_ps2_slv_apb4_i,
  prdata_rng_slv_apb4_i,
  prdata_tim0_slv_apb4_i,
  prdata_tim1_slv_apb4_i,
  prdata_tim2_slv_apb4_i,
  prdata_tim3_slv_apb4_i,
  prdata_psram_slv_apb4_i,
  penable,
  pwrite,
  paddr,
  pwdata,
  pprot,
  pstrb

);


//------------------------------------------------------------------------------
// Parameters
//------------------------------------------------------------------------------

  // User parameters
  parameter ID_WIDTH   = `ID_WIDTH;           // Width of the ID fields
  parameter ADDR_WIDTH = `ADDR_BUS_MAX + 1;   // Width of the address bus

  // Calculated parameters: Do not override
  localparam ID_MAX     = (ID_WIDTH - 1);      // MSB of the ID fields
  localparam ADDR_MAX   = (ADDR_WIDTH - 1);    // MSB of the address bus
  localparam A4K_WIDTH  = 12;                  // Width of 4K address
  localparam A4K_MAX    = (A4K_WIDTH - 1);     // MSB of 4K address


//------------------------------------------------------------------------------
// Port definitions
//------------------------------------------------------------------------------

  // Clock and Reset in AXI domain
  input                 aclk;                 // AXI Bus Clock
  input                 aresetn;              // AXI reset active low

  // A Channel
  input                 awrite;               // R/W address flag
  input     [ID_MAX:0]  aid;                  // R/W address ID
  input   [ADDR_MAX:0]  aaddr;                // R/W address
  input          [7:0]     alen;                 // R/W burst length
  input          [2:0]  asize;                // R/W burst size
  input          [1:0]  aburst;               // R/W burst type
  input          [3:0]  aregion;              // R/W region selection
  input          [2:0]  aprot;                // R/W prot encoding

  input                 avalid;               // R/W address valid
  output                aready;               // R/W address ready

  // D Channel
  output                dbnr;                 // R/B response flag
  output    [ID_MAX:0]  did;                  // R/B response ID
  output        [31:0]  ddata;                // R data
  output         [1:0]  dresp;                // R/B response
  output                dlast;                // R data last
  output                dvalid;               // R/B response valid
  input                 dready;               // R/B response ready

  // W Channel
  input         [31:0]  wdata;                // Write data
  input          [3:0]  wstrb;                // Write data strobe
  input                 wlast;                // Write last
  input                 wvalid;               // Write valid
  output                wready;               // Write ready

  // APB3 Interface
  input                 pclken;               // Clock enable for APB clock
  output                psel_archinfo_slv_apb4_i;     // APB select for slave
  output                psel_crc_slv_apb4_i;     // APB select for slave
  output                psel_spi0_slv_apb4_i;     // APB select for slave
  output                psel_spi1_slv_apb4_i;     // APB select for slave
  output                psel_ps2_slv_apb4_i;     // APB select for slave
  output                psel_rng_slv_apb4_i;     // APB select for slave
  output                psel_tim0_slv_apb4_i;     // APB select for slave
  output                psel_tim1_slv_apb4_i;     // APB select for slave
  output                psel_tim2_slv_apb4_i;     // APB select for slave
  output                psel_tim3_slv_apb4_i;     // APB select for slave
  output                psel_psram_slv_apb4_i;     // APB select for slave
  input                 pready_archinfo_slv_apb4_i;   // APB tx completion for slave
  input                 pready_crc_slv_apb4_i;   // APB tx completion for slave
  input                 pready_spi0_slv_apb4_i;   // APB tx completion for slave
  input                 pready_spi1_slv_apb4_i;   // APB tx completion for slave
  input                 pready_ps2_slv_apb4_i;   // APB tx completion for slave
  input                 pready_rng_slv_apb4_i;   // APB tx completion for slave
  input                 pready_tim0_slv_apb4_i;   // APB tx completion for slave
  input                 pready_tim1_slv_apb4_i;   // APB tx completion for slave
  input                 pready_tim2_slv_apb4_i;   // APB tx completion for slave
  input                 pready_tim3_slv_apb4_i;   // APB tx completion for slave
  input                 pready_psram_slv_apb4_i;   // APB tx completion for slave
  input                 pslverr_archinfo_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_crc_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_spi0_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_spi1_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_ps2_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_rng_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_tim0_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_tim1_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_tim2_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_tim3_slv_apb4_i;  // APB tx response for slave
  input                 pslverr_psram_slv_apb4_i;  // APB tx response for slave
  input         [31:0]  prdata_archinfo_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_crc_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_spi0_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_spi1_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_ps2_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_rng_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_tim0_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_tim1_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_tim2_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_tim3_slv_apb4_i;   // APB read data for slave
  input         [31:0]  prdata_psram_slv_apb4_i;   // APB read data for slave
  output                penable;              // APB Enable
  output                pwrite;               // APB transfer (R/W) direction
  output  [ADDR_MAX:0]  paddr;                // APB address
  output        [31:0]  pwdata;               // APB write data
  output         [2:0]  pprot;                // APB prot encoding
  output         [3:0]  pstrb;                // APB write strobe


//------------------------------------------------------------------------------
// Signal declarations for i/o ports
//------------------------------------------------------------------------------

  // Clock and Reset in AXI domain
  wire                  aclk;                 // AXI Bus Clock
  wire                  aresetn;              // AXI reset active low

  // A Channel
  wire                  awrite;               // R/W address flag
  wire      [ID_MAX:0]  aid;                  // R/W address ID
  wire    [ADDR_MAX:0]  aaddr;                // R/W address
  wire           [7:0]     alen;                 // R/W burst length
  wire           [2:0]  asize;                // R/W burst size
  wire           [1:0]  aburst;               // R/W burst type
  wire           [3:0]  aregion;              // R/W region selection
  wire           [2:0]  aprot;                // R/W prot encoding

  wire                  avalid;               // R/W address valid
  wire                  aready;               // R/W address ready

  // D Channel
  wire                  dbnr;                 // R/B response flag
  wire      [ID_MAX:0]  did;                  // R/B response ID
  wire          [31:0]  ddata;                // R data
  wire           [1:0]  dresp;                // R/B response
  wire                  dlast;                // R data last
  wire                  dvalid;               // R/B response valid
  wire                  dready;               // R/B response ready

  // W Channel
  wire          [31:0]  wdata;                // Write data
  wire           [3:0]  wstrb;                // Write data strobe
  wire                  wlast;                // Write last
  wire                  wvalid;               // Write valid
  wire                  wready;               // Write ready

  // APB3 Interface
  wire                  pclken;               // Clock enable for APB clock
  wire                  psel_archinfo_slv_apb4_i;     // APB select for slave
  wire                  psel_crc_slv_apb4_i;     // APB select for slave
  wire                  psel_spi0_slv_apb4_i;     // APB select for slave
  wire                  psel_spi1_slv_apb4_i;     // APB select for slave
  wire                  psel_ps2_slv_apb4_i;     // APB select for slave
  wire                  psel_rng_slv_apb4_i;     // APB select for slave
  wire                  psel_tim0_slv_apb4_i;     // APB select for slave
  wire                  psel_tim1_slv_apb4_i;     // APB select for slave
  wire                  psel_tim2_slv_apb4_i;     // APB select for slave
  wire                  psel_tim3_slv_apb4_i;     // APB select for slave
  wire                  psel_psram_slv_apb4_i;     // APB select for slave
  wire                  pready_archinfo_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_crc_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_spi0_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_spi1_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_ps2_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_rng_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_tim0_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_tim1_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_tim2_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_tim3_slv_apb4_i;   // APB tx completion for slave
  wire                  pready_psram_slv_apb4_i;   // APB tx completion for slave
  wire                  pslverr_archinfo_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_crc_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_spi0_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_spi1_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_ps2_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_rng_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_tim0_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_tim1_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_tim2_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_tim3_slv_apb4_i;  // APB tx response for slave
  wire                  pslverr_psram_slv_apb4_i;  // APB tx response for slave
  wire          [31:0]  prdata_archinfo_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_crc_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_spi0_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_spi1_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_ps2_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_rng_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_tim0_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_tim1_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_tim2_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_tim3_slv_apb4_i;   // APB read data for slave
  wire          [31:0]  prdata_psram_slv_apb4_i;   // APB read data for slave
  wire                  penable;              // APB Enable
  wire                  pwrite;               // APB transfer (R/W) direction
  wire    [ADDR_MAX:0]  paddr;                // APB address
  wire          [31:0]  pwdata;               // APB write data

  wire           [2:0]  pprot;                // APB prot encoding
  wire           [3:0]  pstrb;                // APB write strobe



//------------------------------------------------------------------------------
//
//                nic400_amib_perip1_gp_apb4_apb_m_ysyx_rv32
//                ============================
//
//------------------------------------------------------------------------------
//   The 16-Slot APB Bridge provides an interface between the high-speed AXI 
// domain and the low-power APB domain. The Bridge appears as a slave on AXI, 
// whereas on APB, it is the master. Read and write transfers on the AXI are 
// converted into corresponding transfers on the APB. As the APB is not 
// pipelined, wait states are added during transfers to and from the APB when 
// the AXI is required to wait for the APB protocol.
//
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Wire declarations
//------------------------------------------------------------------------------
  wire    [ADDR_MAX:0]  incremented_addr;     // Incremented address derived by function call

//------------------------------------------------------------------------------
//
// Main body of code
// =================
//
//------------------------------------------------------------------------------

  reg           bridge_state;       //Bridge state
  reg           nxt_bridge_state;   //Bridge state
  wire          bridge_state_en;    //Enable for the bridge state machine
  
  

  //Internal APB signals
  reg  [ADDR_MAX:0]    nxt_paddr;
  reg  [ADDR_MAX:0]    paddr_i;
  reg  [11:0]             psel_i;
  reg  [11:0]             nxt_psel;
  wire [11:0]             psel_dec;

  reg                  nxt_penable;
  reg                  penable_i;
  reg                  nxt_pwrite;
  reg                  pwrite_i;
  reg [2:0]            pprot_i;
  reg [2:0]            nxt_pprot;
  reg [3:0]            nxt_pstrb;
  reg [3:0]            pstrb_i;
  reg [31:0]           nxt_pwdata;
  reg [31:0]           pwdata_i;
 
  //Other information stored about the burst
  reg                  last_beat;
  reg                  nxt_last_beat;
  reg [2:0]            axi_size;
  reg [2:0]            nxt_axi_size;
  reg [3:0]            axi_region;
  wire [3:0]           nxt_axi_region;
  reg [1:0]            axi_burst;
  reg [1:0]            nxt_axi_burst;
  
  reg [ID_MAX:0]           axi_id;
  reg [ID_MAX:0]           nxt_axi_id;
  reg [7:0]               axi_len;
  reg [7:0]               nxt_axi_len;
  reg [7:0]               axi_len_count;
  reg [7:0]               nxt_axi_len_count;
  
  //Other control signals
  wire                 ok_to_start_nxt_apb_trans;
  reg                  abeat_used_axi;
  reg                  abeat_used_apb;
  reg                  nxt_abeat_used_apb;
  reg                  wbeat_used_axi;
  reg                  wbeat_used_apb;
  reg                  nxt_wbeat_used_apb;
  wire                 pready_or_idle;
  wire                 no_strb_write;                 
  wire                 burst_in_progress;
  wire                 pready;
  wire                 pslverr;
  wire [31:0]          prdata;

  //Data capture signal
  wire                 data_capture_en;
  reg [31:0]           apb_prdata_reg;
  reg                  apb_pslverr_reg;
  reg                  apb_last_reg;
  reg                  apb_pwrite_reg;
  
  reg [ID_MAX:0]            apb_id_reg;
  
  reg                  data_avail_apb;
  wire                 nxt_data_avail_apb;

  wire                 apb_data_accept;
  reg                  data_avail_axi;
  wire                 axi_resp_valid;
  wire                 axi_resp_ready;

  wire                 err_acc_en;
  wire                 next_accumulated_err;
  reg                  accumulated_err;
  wire [38:0]       axi_resp_payload_in;
  wire [38:0]       axi_resp_payload_out;

  //----------------------------------------------------------------------------
  // Instantiation of Combinatorial address incrementer
  // Inputs passed to the instance are 
  // paddr_i   --> Current address which needs to be incremented for next
  //               transfer.
  // axi_len   --> Length of AXI transfer, which was registered in the APB set
  //               up phase. This information is required for WRAP transfers.
  // axi_size  --> AXI transfer width, which was registered in the APB set up
  //               phase. Values can be 8/16/32 bit.
  // brst_type --> AXI burst information, which was registered in the APB set
  //               up phase. Values can be FIXED/INCR/WRAP transfers.
  //----------------------------------------------------------------------------
  nic400_amib_perip1_gp_apb4_a_gen_ysyx_rv32 #(
    .ADDR_WIDTH     (A4K_WIDTH)
  ) u_a_gen
  (
    .addr_in        (paddr_i[A4K_MAX:0]),
    .alen           (axi_len[3:0]),
    .asize          (axi_size),
    .aburst         (axi_burst),

    .addr_out       (incremented_addr[A4K_MAX:0])
  );

  //----------------------------------------------------------------------------
  // Upper address bits are unchanged
  //----------------------------------------------------------------------------
  assign incremented_addr[ADDR_MAX:A4K_WIDTH] = paddr_i[ADDR_MAX:A4K_WIDTH];

  //----------------------------------------------------------------------------
  // Create a flag to indicate that a burst is in progress. This is when the 
  // axi_len counter is not 0
  //----------------------------------------------------------------------------
  assign burst_in_progress = |axi_len_count;

  //----------------------------------------------------------------------------
  // An APB write transaction should not occur if the strobes are all 0 
  //----------------------------------------------------------------------------
  assign no_strb_write = (burst_in_progress) ? pwrite_i & ~|wstrb :
                                               ((wvalid & ~|wstrb) & (avalid & awrite));

  //----------------------------------------------------------------------------
  // Decode the next PSEL value. This will be according to the region and 
  // the strobes of any incoming write data
  //----------------------------------------------------------------------------
  assign nxt_axi_region = (burst_in_progress) ? axi_region: aregion;
  assign psel_dec[0] = (nxt_axi_region == `AMIB_S0_REGION) & ~no_strb_write;
  assign psel_dec[1] = (nxt_axi_region == `AMIB_S1_REGION) & ~no_strb_write;
  assign psel_dec[2] = (nxt_axi_region == `AMIB_S2_REGION) & ~no_strb_write;
  assign psel_dec[3] = (nxt_axi_region == `AMIB_S3_REGION) & ~no_strb_write;
  assign psel_dec[4] = (nxt_axi_region == `AMIB_S4_REGION) & ~no_strb_write;
  assign psel_dec[5] = (nxt_axi_region == `AMIB_S5_REGION) & ~no_strb_write;
  assign psel_dec[6] = (nxt_axi_region == `AMIB_S6_REGION) & ~no_strb_write;
  assign psel_dec[7] = (nxt_axi_region == `AMIB_S7_REGION) & ~no_strb_write;
  assign psel_dec[8] = (nxt_axi_region == `AMIB_S8_REGION) & ~no_strb_write;
  assign psel_dec[9] = (nxt_axi_region == `AMIB_S9_REGION) & ~no_strb_write;
  assign psel_dec[10] = (nxt_axi_region == `AMIB_S10_REGION) & ~no_strb_write;
  assign psel_dec[11] = ~|psel_dec[10:0];


  //----------------------------------------------------------------------------
  // Determine when it's safe to start a new APB transaction .. which is:
  // 1) There is space in the AXI output buffer
  // 2) The apb bus is idle or ready is being received
  // 3) There's something to do and
  // 4) write data is available if it's a write 
  //----------------------------------------------------------------------------
  assign pready_or_idle = pready | ~(|psel_i);

  assign ok_to_start_nxt_apb_trans = axi_resp_ready & pready_or_idle &
                                     ((burst_in_progress) ? (~pwrite_i | wvalid) : (avalid & (~awrite | wvalid)));
                                     
  //----------------------------------------------------------------------------
  // This block registers D-Input logic used in apb_bridge_sm_conv process.
  // All the flops are clocked using pclken
  //----------------------------------------------------------------------------

  always @*
    begin : app_bridge_sm_comb
    
      nxt_bridge_state   = bridge_state;   // Default value
      nxt_psel           = psel_i;         // Default value
      nxt_penable        = penable_i;
      nxt_paddr          = paddr_i;        // Default value
      nxt_pwrite         = pwrite_i;       // Default value
      nxt_pprot          = pprot_i;        // Default value
      nxt_pstrb          = pstrb_i;        // Default value
      nxt_pwdata         = pwdata_i;       // Default value

      nxt_last_beat      = last_beat;
      nxt_axi_size       = axi_size;
      nxt_axi_burst      = axi_burst;
      nxt_axi_len        = axi_len;
      nxt_axi_len_count  = axi_len_count;
      
      nxt_axi_id         = axi_id;

      nxt_abeat_used_apb = abeat_used_apb; 
      nxt_wbeat_used_apb = wbeat_used_apb;

      
      case (bridge_state)
      
        //State is everything apart from 1st cycle
        1'b0 : 
          begin
          
            if (ok_to_start_nxt_apb_trans) begin
                
               //Start an APB transfer .. so record all AXI information
               nxt_psel     = psel_dec;
               nxt_penable  = 1'b0;
               nxt_paddr    = (burst_in_progress) ? incremented_addr : aaddr;
               nxt_pwrite   = (burst_in_progress) ? pwrite_i : awrite;
               nxt_pprot    = (burst_in_progress) ? pprot_i : aprot;

               nxt_last_beat     = (burst_in_progress) ? (axi_len_count == 'd1) : ~|alen;
               nxt_axi_burst     = (burst_in_progress) ? axi_burst : aburst;     
               nxt_axi_len       = (burst_in_progress) ? axi_len : alen;
               nxt_axi_size      = (burst_in_progress) ? axi_size : asize;
               nxt_axi_len_count = (burst_in_progress) ? axi_len_count - 'd1 : alen;
               
               nxt_axi_id        = (burst_in_progress) ? axi_id : aid;
               

               //Now toggle nxt_abeat_used_apb to indicate use of AXI address beat if one was used
               nxt_abeat_used_apb = (burst_in_progress) ? abeat_used_apb : ~abeat_used_apb;

               //Set up the write data - ok_to_start_nxt_apb_trans ensures data is available 
               if (nxt_pwrite) begin
                   
                  nxt_pwdata = wdata;
                  nxt_pstrb  = wstrb;

                  //Now toggle nxt_abeat_used_axi to indicate use of AXI address beat
                  nxt_wbeat_used_apb = ~wbeat_used_apb;
                   
               end  else begin
                   
                   //read hence set strobes to 0
                   nxt_pstrb  = 4'b0000;
                   
               end 
                
               //Move state
               nxt_bridge_state = 1'b1;
              
            end else begin

                //If a transaction is in progress (PSEL != 0) then complete transaction on
                //pready else drive to 0
                nxt_psel     = (|psel_i) ? {12{~pready}} & psel_i : {12{1'b0}};
                nxt_penable  = (|psel_i) ? ~pready : 1'b0;

            end    
          end
 
        1'b1:
          begin
                //Set PENABLE to 1 and move to next state
                nxt_penable = 1'b1;
                nxt_bridge_state = 1'b0;
          end

        default :
             nxt_bridge_state = 1'bx;

      endcase
    end // apb_bridge_sm_comb

  //----------------------------------------------------------------------------
  // This block registers D-Input logic used in apb_bridge_sm_conv process.
  // 
  // SM is clocked on enabled edges only (to prevent metastability issues of
  // using pready). PSEL_i, avalid and busrt_in_progress are also used to save power. These are
  // all fast clock signals
  //----------------------------------------------------------------------------

  assign bridge_state_en = pclken & (avalid | (|psel_i) | burst_in_progress);

  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_apb_sm_seq
      if (!aresetn)
        begin
           bridge_state   <= 1'b0; 
           psel_i         <= 'd0;    
           penable_i      <= 1'b0;
           paddr_i        <= 'd0;
           pwrite_i       <= 1'd0;
           pprot_i        <= 3'b0;       
           pstrb_i        <= 4'b0;
           pwdata_i       <= 32'b0;
           last_beat      <= 1'b0;
           axi_size       <= 3'b0;
           axi_burst      <= 2'b0;
           axi_len        <= 'd0;
           axi_len_count  <= 'd0;
           axi_id         <= 'd0;
           axi_region     <= 4'd0;
           wbeat_used_apb <= 1'b0;
           abeat_used_apb <= 1'b0;
        end
      else if (bridge_state_en) 
        begin
           bridge_state   <= nxt_bridge_state;
           psel_i         <= nxt_psel;       
           penable_i      <= nxt_penable;
           paddr_i        <= nxt_paddr;     
           pwrite_i       <= nxt_pwrite;
           pprot_i        <= nxt_pprot;      
           pstrb_i        <= nxt_pstrb; 
           pwdata_i       <= nxt_pwdata;       
           last_beat      <= nxt_last_beat;
           axi_size       <= nxt_axi_size;
           axi_burst      <= nxt_axi_burst;
           axi_len        <= nxt_axi_len;
           axi_len_count  <= nxt_axi_len_count;
           axi_id         <= nxt_axi_id;
           axi_region     <= nxt_axi_region;
           wbeat_used_apb <= nxt_wbeat_used_apb;
           abeat_used_apb <= nxt_abeat_used_apb;
        end
    end // p_bridge_apb_sm_seq

  //----------------------------------------------------------------------------
  // Axi Forward channel ready generation (control from state machine)
  //----------------------------------------------------------------------------
  assign aready  = abeat_used_apb ^ abeat_used_axi;

  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_abeat_use
      if (!aresetn)
        begin
           abeat_used_axi <= 1'b0;
        end
      else if (aready)
        begin
           abeat_used_axi <= ~abeat_used_axi;
        end
    end // p_bridge_abeat_use

  assign wready  = wbeat_used_apb ^ wbeat_used_axi;

  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_wbeat_use
      if (!aresetn)
        begin
           wbeat_used_axi <= 1'b0;
        end
      else if (wready)
        begin
           wbeat_used_axi <= ~wbeat_used_axi;
        end
    end // p_bridge_wbeat_use

  
  //----------------------------------------------------------------------------
  // Assigning psel for 11 APB slaves
  //----------------------------------------------------------------------------
  
  assign psel_archinfo_slv_apb4_i = psel_i[0];
  assign psel_crc_slv_apb4_i = psel_i[1];
  assign psel_spi0_slv_apb4_i = psel_i[2];
  assign psel_spi1_slv_apb4_i = psel_i[3];
  assign psel_ps2_slv_apb4_i = psel_i[4];
  assign psel_rng_slv_apb4_i = psel_i[5];
  assign psel_tim0_slv_apb4_i = psel_i[6];
  assign psel_tim1_slv_apb4_i = psel_i[7];
  assign psel_tim2_slv_apb4_i = psel_i[8];
  assign psel_tim3_slv_apb4_i = psel_i[9];
  assign psel_psram_slv_apb4_i = psel_i[10];

  //----------------------------------------------------------------------------
  // ORed prdata/pready/pslverr lines
  //----------------------------------------------------------------------------
  assign prdata = (prdata_archinfo_slv_apb4_i & {32{psel_archinfo_slv_apb4_i}}) |
                  (prdata_crc_slv_apb4_i & {32{psel_crc_slv_apb4_i}}) |
                  (prdata_spi0_slv_apb4_i & {32{psel_spi0_slv_apb4_i}}) |
                  (prdata_spi1_slv_apb4_i & {32{psel_spi1_slv_apb4_i}}) |
                  (prdata_ps2_slv_apb4_i & {32{psel_ps2_slv_apb4_i}}) |
                  (prdata_rng_slv_apb4_i & {32{psel_rng_slv_apb4_i}}) |
                  (prdata_tim0_slv_apb4_i & {32{psel_tim0_slv_apb4_i}}) |
                  (prdata_tim1_slv_apb4_i & {32{psel_tim1_slv_apb4_i}}) |
                  (prdata_tim2_slv_apb4_i & {32{psel_tim2_slv_apb4_i}}) |
                  (prdata_tim3_slv_apb4_i & {32{psel_tim3_slv_apb4_i}}) |
                  (prdata_psram_slv_apb4_i & {32{psel_psram_slv_apb4_i}});

  assign pslverr = ((pslverr_archinfo_slv_apb4_i & psel_archinfo_slv_apb4_i) |
                     (pslverr_crc_slv_apb4_i & psel_crc_slv_apb4_i) |
                     (pslverr_spi0_slv_apb4_i & psel_spi0_slv_apb4_i) |
                     (pslverr_spi1_slv_apb4_i & psel_spi1_slv_apb4_i) |
                     (pslverr_ps2_slv_apb4_i & psel_ps2_slv_apb4_i) |
                     (pslverr_rng_slv_apb4_i & psel_rng_slv_apb4_i) |
                     (pslverr_tim0_slv_apb4_i & psel_tim0_slv_apb4_i) |
                     (pslverr_tim1_slv_apb4_i & psel_tim1_slv_apb4_i) |
                     (pslverr_tim2_slv_apb4_i & psel_tim2_slv_apb4_i) |
                     (pslverr_tim3_slv_apb4_i & psel_tim3_slv_apb4_i) |
                     (pslverr_psram_slv_apb4_i & psel_psram_slv_apb4_i));

  assign pready = (pready_archinfo_slv_apb4_i & psel_archinfo_slv_apb4_i) |
                  (pready_crc_slv_apb4_i & psel_crc_slv_apb4_i) |
                  (pready_spi0_slv_apb4_i & psel_spi0_slv_apb4_i) |
                  (pready_spi1_slv_apb4_i & psel_spi1_slv_apb4_i) |
                  (pready_ps2_slv_apb4_i & psel_ps2_slv_apb4_i) |
                  (pready_rng_slv_apb4_i & psel_rng_slv_apb4_i) |
                  (pready_tim0_slv_apb4_i & psel_tim0_slv_apb4_i) |
                  (pready_tim1_slv_apb4_i & psel_tim1_slv_apb4_i) |
                  (pready_tim2_slv_apb4_i & psel_tim2_slv_apb4_i) |
                  (pready_tim3_slv_apb4_i & psel_tim3_slv_apb4_i) |
                  (pready_psram_slv_apb4_i & psel_psram_slv_apb4_i) |
                  psel_i[11];
  
  
  //----------------------------------------------------------------------------
  // Return data capture - APB side
  //
  // Data is capture on every enabled edge when psel and penable are high.
  // It is then determined whether the data is ready to be used or not.
  // This is safer than simply using pready as a gating term as this could
  // introduce metastability issues when the connected slave is slower than
  // the brodge
  //
  // If PREADY is high when data is captured then an XOR causes toggles
  // data_avail_apb. A difference between data_avail_apb and data_avail_axi
  // indicates that there is valid data to be taken here.
  // Note that the AXI skid buffer (see below) is checked for space before the
  // APB transaction starts so there is no risk of overwriting the data before
  // it's removed.
  //----------------------------------------------------------------------------

  assign data_capture_en = pclken & |psel_i & penable_i;
  assign nxt_data_avail_apb = data_avail_apb ^ pready;
 
  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_data_capture
      if (!aresetn)
        begin
          apb_prdata_reg  <= {32{1'b0}};
          apb_pslverr_reg <= 1'b0;
          apb_last_reg    <= 1'b0;
          apb_pwrite_reg  <= 1'b0;
          apb_id_reg      <= 'd0;
          data_avail_apb  <= 1'b0;
        end
      else if (data_capture_en)
        begin
          apb_prdata_reg  <= prdata;
          apb_pslverr_reg <= pslverr;
          apb_last_reg    <= last_beat;
          apb_pwrite_reg  <= pwrite_i;
          apb_id_reg      <= axi_id;
          data_avail_apb  <= nxt_data_avail_apb;
        end
    end // p_bridge_data_capture

  //----------------------------------------------------------------------------
  // Return data capture - AXI side + Error accumulator
  //----------------------------------------------------------------------------

  //----------------------------------------------------------------------------
  // As Writes only have one response (on last) accumulate all responses from
  // early beats so any error results in a final error. 
  // Clear when last beat is passed to AXI or buffer
  //----------------------------------------------------------------------------
  assign err_acc_en = apb_pwrite_reg & (data_avail_apb ^ data_avail_axi) & (axi_resp_ready | ~apb_last_reg);

  assign next_accumulated_err = (apb_last_reg) ? 1'b0 : accumulated_err | apb_pslverr_reg;

  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_err_acc
      if (!aresetn)
        begin
           accumulated_err <= 1'b0;
        end
      else if (err_acc_en)
        begin
           accumulated_err <= next_accumulated_err;
        end
    end // p_bridge_err_acc

  //----------------------------------------------------------------------------
  // Pass data beat out to AXI when 
  // 1) There is data available .. and
  // 2) It's a read .. or the last beat of a write
  //----------------------------------------------------------------------------
  assign axi_resp_valid = (data_avail_apb ^ data_avail_axi) & (~apb_pwrite_reg | apb_last_reg);

  assign axi_resp_payload_in = {apb_pwrite_reg, 
                                apb_last_reg, 
                                apb_pslverr_reg | accumulated_err,
                                apb_id_reg,
                                apb_prdata_reg};

  //----------------------------------------------------------------------------
  // data_avail_axi - Toggling register to confirm acceptance of data from apb
  // Data is accepted and passed to AXI or error accumulator
  //----------------------------------------------------------------------------

  assign apb_data_accept = (data_avail_apb ^ data_avail_axi) & ((axi_resp_valid & axi_resp_ready) || (apb_pwrite_reg & ~apb_last_reg));

  always @(posedge aclk or negedge aresetn)
    begin : p_bridge_apb_data_accept
      if (!aresetn)
        begin
           data_avail_axi <= 1'b0;
        end
      else if (apb_data_accept)
        begin
           data_avail_axi <= ~data_avail_axi;
        end
    end // p_bridge_err_acc

  //----------------------------------------------------------------------------
  // Reverse channel Buffer and AXI outputs
  // 
  // Buffer on the output enables bacl-to-back APB transactions
  //----------------------------------------------------------------------------
  nic400_rev_regd_slice_ysyx_rv32 #(39) u_axi_resp_ouput_buffer
  (
  // global signals
    .aresetn           (aresetn),
    .aclk              (aclk),

  // Inputs
    .valid_src         (axi_resp_valid),
    .ready_dst         (dready),
    .payload_src       (axi_resp_payload_in),

  // outputs
    .valid_dst         (dvalid),
    .ready_src         (axi_resp_ready),
    .payload_dst       (axi_resp_payload_out)
  );

  assign {dbnr, dlast, dresp[1], did, ddata} = axi_resp_payload_out;
  assign dresp[0] = 1'b0;

  //----------------------------------------------------------------------------
  // Assigning internal copies to output ports
  //----------------------------------------------------------------------------
  assign pwrite  = pwrite_i;
  assign paddr   = paddr_i;
  assign penable = penable_i;
  assign pwdata  = pwdata_i;

  assign pprot   = pprot_i;
  assign pstrb   = pstrb_i;



//==============================================================================
// OVL Assertions
//==============================================================================


`ifdef ARM_ASSERT_ON

// Include Standard OVL Defines
`include "std_ovl_defines.h"


  //----------------------------------------------------------------------------
  // OVL_ASSERT: Check the value of asize is set to a supported value
  //----------------------------------------------------------------------------
  // Design only supports asize being set to 8, 16, 32
  //----------------------------------------------------------------------------
  // OVL_ASSERT_RTL
  assert_never #(`OVL_ERROR, `OVL_ASSERT,
                 "Value of asize not supported")
  amib_apb_illegal_asize
  (
    .clk            (aclk),
    .reset_n        (aresetn),
    .test_expr      (avalid && aready &&
                     ((asize == `AXI_ASIZE_64)  || 
                      (asize == `AXI_ASIZE_128) ||
                      (asize == `AXI_ASIZE_256) ||
                      (asize == `AXI_ASIZE_512) ||
                      (asize == `AXI_ASIZE_1024)))
  );
  // OVL_ASSERT_END

  //----------------------------------------------------------------------------
  // OVL_ASSERT: Check for unknown APB psel regions
  //----------------------------------------------------------------------------
  // Design only supports configured APB psel regions
  //----------------------------------------------------------------------------
  // OVL_ASSERT_RTL
   assert_zero_one_hot #(0,12,0,"ERROR, More than one psel selected")
     ovl_multi_psel_output
       (
        .clk       (aclk),
        .reset_n   (aresetn),
        .test_expr (psel_i)
        );

  // OVL_ASSERT_END

`ifdef ARM_OVL_IGNORE_UNALIGN
  //----------------------------------------------------------------------------
  // Inform if unalignment OVLs are disabled
  //----------------------------------------------------------------------------
  initial
    begin : p_arm_ovl_ignore_unalign
      $display("ARM_OVL_IGNORE_UNALIGN: Unalignment OVLs are disabled in %m");
    end // p_arm_ovl_ignore_unalign
`else
  //----------------------------------------------------------------------------
  // OVL_ASSERT: Check for zero strobe writes
  //----------------------------------------------------------------------------
  // Design ignores zero strobe writes
  //----------------------------------------------------------------------------
  // OVL_ASSERT_RTL
  assert_never #(`OVL_WARNING, `OVL_ASSERT,
                 "Zero-strobe writes will be ignored by APB MIB")
  amib_apb_zero_wstrb
  (
    .clk            (aclk),
    .reset_n        (aresetn),
    .test_expr      (wvalid && wready && (wstrb == 4'b0000))
  );
  // OVL_ASSERT_END

  //----------------------------------------------------------------------------
  // OVL_ASSERT: Check for no meta-stability
  //----------------------------------------------------------------------------
  // Design ignores zero strobe writes
  //----------------------------------------------------------------------------
  // OVL_ASSERT_RTL
  assert_never #(`OVL_WARNING, `OVL_ASSERT,
                 "apb capture when axi not ready")
  amib_axi_apb_hshake
  (
    .clk            (aclk),
    .reset_n        (aresetn),
    .test_expr      (data_capture_en && (data_avail_apb != data_avail_axi))
  );
  // OVL_ASSERT_END


`endif // ARM_OVL_IGNORE_UNALIGN

`endif // ARM_ASSERT_ON


endmodule // nic400_amib_perip1_gp_apb4_apb_m_ysyx_rv32


//------------------------------------------------------------------------------
// AMIB Undefines
//------------------------------------------------------------------------------
`include "nic400_amib_perip1_gp_apb4_undefs_ysyx_rv32.v"
`include "Axi_undefs.v"


//------------------------------------------------------------------------------
// End of File
//------------------------------------------------------------------------------

